package org.example.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;
import org.example.entity.InvestmentCountData;
import org.example.entity.InvestmentReturnData;
import org.example.service.ExcelService;
import org.example.service.InvestmentCountDataService;
import org.example.service.InvestmentReturnDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Excel导入导出服务实现类
 */
@Slf4j
@Service
public class ExcelServiceImpl implements ExcelService {
    
    @Autowired
    private InvestmentReturnDataService investmentReturnDataService;
    @Autowired
    private InvestmentCountDataService investmentCountDataService;
    
    /**
     * 批量处理的数据量
     */
    private static final int BATCH_COUNT = 100;
    
    /**
     * 支持的类别类型
     */
    private static final List<String> SUPPORTED_CATEGORIES = Arrays.asList("30+金额", "60+金额", "90+金额");
    /**
     * vangate笔数
     */
    private static final List<String> BATCH_SUPPORTED_CATEGORIES = Arrays.asList("30+笔数", "60+笔数", "90+笔数");
    
    @Override
    public int importExcel(MultipartFile file, String categoryType) throws IOException {
        // 验证类别类型
        if (!SUPPORTED_CATEGORIES.contains(categoryType)) {
            throw new IllegalArgumentException("不支持的类别类型: " + categoryType + "，支持的类别: " + SUPPORTED_CATEGORIES);
        }
        
        // 清空该类别下的现有数据
        investmentReturnDataService.clearByCategoryType(categoryType);
        
        final List<InvestmentReturnData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        final int[] totalCount = {0};
        
        EasyExcel.read(file.getInputStream(), InvestmentReturnData.class, new ReadListener<InvestmentReturnData>() {
            @Override
            public void invoke(InvestmentReturnData data, AnalysisContext context) {
                // 设置类别类型
                data.setCategoryType(categoryType);
                data.setCreatedTime(LocalDateTime.now());
                data.setUpdatedTime(LocalDateTime.now());
                
                cachedDataList.add(data);
                
                // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
                if (cachedDataList.size() >= BATCH_COUNT) {
                    saveData();
                    // 存储完成清理 list
                    cachedDataList.clear();
                }
            }
            
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                // 这里也要保存数据，确保最后遗留的数据也存储到数据库
                saveData();
                log.info("Excel导入完成，共处理 {} 条数据", totalCount[0]);
            }
            
            private void saveData() {
                if (!cachedDataList.isEmpty()) {
                    investmentReturnDataService.batchSave(new ArrayList<>(cachedDataList));
                    totalCount[0] += cachedDataList.size();
                    log.info("已保存 {} 条数据", cachedDataList.size());
                }
            }
        }).sheet().doRead();
        
        return totalCount[0];
    }
    
    @Override
    public void exportExcel(String categoryType, HttpServletResponse response) throws IOException {
        // 验证类别类型
        if (!SUPPORTED_CATEGORIES.contains(categoryType)) {
            throw new IllegalArgumentException("不支持的类别类型: " + categoryType + "，支持的类别: " + SUPPORTED_CATEGORIES);
        }
        
        // 查询数据
        List<InvestmentReturnData> dataList = investmentReturnDataService.getByCategoryType(categoryType);
        
        // 设置响应头
        String fileName = URLEncoder.encode("投资收益率数据_" + categoryType, StandardCharsets.UTF_8);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        
        // 写入Excel
        EasyExcel.write(response.getOutputStream(), InvestmentReturnData.class)
                .sheet(categoryType)
                .doWrite(dataList);
    }
    
    @Override
    public void exportAllCategoriesExcel(HttpServletResponse response) throws IOException {
        // 设置响应头
        String fileName = URLEncoder.encode("投资收益率数据_全部类别", StandardCharsets.UTF_8);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        
        // 创建Excel写入器
        try (var excelWriter = EasyExcel.write(response.getOutputStream(), InvestmentReturnData.class).build()) {
            // 为每个类别创建一个sheet
            for (String categoryType : SUPPORTED_CATEGORIES) {
                List<InvestmentReturnData> dataList = investmentReturnDataService.getByCategoryType(categoryType);
                
                // 写入对应的sheet
                var writeSheet = EasyExcel.writerSheet(categoryType).build();
                excelWriter.write(dataList, writeSheet);
            }
        }
    }

    @Override
    public int batchImportExcel(MultipartFile file, String categoryType) throws IOException {
        // 验证类别类型
        if (!BATCH_SUPPORTED_CATEGORIES.contains(categoryType)) {
            throw new IllegalArgumentException("不支持的类别类型: " + categoryType + "，支持的类别: " + BATCH_SUPPORTED_CATEGORIES);
        }

        // 清空该类别下的现有数据
        investmentCountDataService.clearByCategoryType(categoryType);

        final List<InvestmentCountData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        final int[] totalCount = {0};

        EasyExcel.read(file.getInputStream(), InvestmentCountData.class, new ReadListener<InvestmentCountData>() {
            @Override
            public void invoke(InvestmentCountData data, AnalysisContext context) {
                // 设置类别类型
                data.setCategoryType(categoryType);
                data.setCreatedTime(LocalDateTime.now());
                data.setUpdatedTime(LocalDateTime.now());

                cachedDataList.add(data);

                // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
                if (cachedDataList.size() >= BATCH_COUNT) {
                    saveData();
                    // 存储完成清理 list
                    cachedDataList.clear();
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                // 这里也要保存数据，确保最后遗留的数据也存储到数据库
                saveData();
                log.info("Excel导入完成，共处理 {} 条数据", totalCount[0]);
            }

            private void saveData() {
                if (!cachedDataList.isEmpty()) {
                    investmentCountDataService.batchSave(new ArrayList<>(cachedDataList));
                    totalCount[0] += cachedDataList.size();
                    log.info("已保存 {} 条数据", cachedDataList.size());
                }
            }
        }).sheet().doRead();

        return totalCount[0];
    }
}
